<template>
  <div class="design-index">
    <a-card title="Ant-Design  Vue3-Form-Design">
      <template #extra>
        <a-button type="primary" @click="preview">预览</a-button>
      </template>
    </a-card>
    <div class="form-design">
      <!-- 左侧控件列表 start-->
      <div class="form-design-left">
        <div class="left-scrollbar">
          <div class="components-list">
            <div v-for="(item, listIndex) in data_.compsList" :key="listIndex">
              <div class="components-title">
                <PicRightOutlined />
                {{ item.title }}
              </div>
              <template v-if="item.list?.length">
                <draggable class="components-draggable" :list="item.list" itemKey="id"
                  :group="{ name: 'compsGroup', pull: 'clone', put: false }" :clone="dragAndClone"
                  draggable=".components-item" :sort="false" @end="onEnd">
                  <template #item="{ element, index }">
                    <div :key="index" class="components-item">
                      <div class="components-info">
                        <PicCenterOutlined />
                        {{ element.__config__.label }}
                      </div>
                    </div>
                  </template>
                </draggable>
              </template>
              <template v-else>
                <a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" description="待开发" />
              </template>
            </div>
          </div>
        </div>
      </div>
      <!-- 左侧控件列表 end-->
      <!-- 中间控件列表 start-->
      <div class="form-design-center">
        <div class="center-scrollbar">
          <a-row class="form-design-center-row" :gutter="data_.formConf.gutter">
            <a-form :labelAlign="data_.formConf.labelAlign">
              <draggable class="draggable-box" :list="data_.dragingList" itemKey="id" :animation="340" group="compsGroup">
                <template #item="{ element, index }">
                  <form-item :key="element.renderKey" :item-list="data_.dragingList" :item="element" :index="index"
                    :active-id="data_.activeId" @activeItem="activeDragingItem" @copyItem="copyDragingItem"
                    @deleteItem="deleteDragingItem" />
                </template>
              </draggable>
              <div v-show="!data_.dragingList.length" class="empty-info">
                <a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" description="从左侧拖入组件进行表单设计" />
              </div>
            </a-form>
          </a-row>
        </div>
      </div>
      <!-- 中间控件列表 end-->
      <!-- 右侧属性列表 start-->
      <form-item-attr :active-data="data_.activeItem" :form-conf="data_.formConf" />
      <input id="copyNode" type="hidden">
      <!-- 右侧属性列表 end-->
      <a-drawer title="表单预览" width="50%" :visible="data_.visible" destroyOnClose @close="closeView">
        <form-view :viewData="preViewData" ref="preViewRef" />
        <template #extra>
          <a-space>
            <a-button @click="closeView">取消</a-button>
            <a-button type="primary" @click="viewSubmit">提交</a-button>
          </a-space>
        </template>
      </a-drawer>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { nextTick, reactive, ref, watch } from 'vue'
import { Empty, message } from 'ant-design-vue';
import { PicRightOutlined, PicCenterOutlined } from '@ant-design/icons-vue';
import { cloneDeep } from 'lodash-es'
import draggable from 'vuedraggable'
import formItem from '../components/form-item/index.vue'
import formItemAttr from '../components/form-item-attr/index.vue'
import formView from '../components/form-view/index.vue'
import { baseCompsList, formConf } from '../common/config'


let oldActiveId: any = null,
  tempActiveData: any = null;

const data_ = reactive<any>({
  idGlobal: 100,
  formConf,
  dragingList: [],
  activeId: 0,
  activeItem: null,
  compsList: [
    {
      title: '基础控件',
      list: baseCompsList
    },
    {
      title: '高级控件',
      list: []
    },
    {
      title: '系统控件',
      list: []
    },
    {
      title: '布局控件',
      list: []
    }
  ],
  title: '预览',
  visible: false,
})
// 预览数据
const preViewData: any = ref()

watch(() => 'data_.activeItem.__config__.label', (val, oldVal) => {
  if (data_.activeItem.placeholder === undefined || !data_.activeItem.__config__.tag || oldActiveId !== data_.activeId) return;
  data_.activeItem.placeholder = data_.activeItem.placeholder.replace(oldVal, '') + val
})

watch(() => data_.activeId, (val) => {
  oldActiveId = val
}, {
  immediate: true
})

const activeDragingItem = (item: any) => {
  data_.activeItem = item
  data_.activeId = item.__config__.formId
}
const onEnd = (obj: any) => {
  if (obj.from !== obj.to) {
    data_.activeItem = tempActiveData
    data_.activeId = data_.idGlobal
  }
}
const dragAndClone = (origin: any) => {
  const clone = cloneDeep(origin)
  const config = clone.__config__
  config.span = data_.formConf.span
  createIdAndKey(clone)
  clone.placeholder !== undefined && (clone.placeholder += config.label)
  tempActiveData = clone
  return tempActiveData
}
const createIdAndKey = (item: any) => {
  const config = item.__config__
  config.formId = ++data_.idGlobal
  config.renderKey = `${config.formId}${+new Date()}`
  if (config.layout === 'colFormItem') {
    item.__vModel__ = `field${data_.idGlobal}`
  } else if (config.layout === 'rowFormItem') {
    config.componentName = `row${data_.idGlobal}`
    !Array.isArray(config.children) && (config.children = [])
    delete config.label // rowFormItem无需配置label属性
  }
  if (Array.isArray(config.children)) {
    config.children = config.children.map((childItem: any) => createIdAndKey(childItem))
  }
  return item
}
const copyDragingItem = (item: any, list: any) => {
  let clone = cloneDeep(item)
  clone = createIdAndKey(clone)
  list.push(clone)
  activeDragingItem(clone)
}
const deleteDragingItem = (index: any, list: any) => {
  list.splice(index, 1)
  nextTick(() => {
    const len = data_.dragingList.length
    if (len) {
      activeDragingItem(data_.dragingList[len - 1])
    } else {
      data_.activeItem = null
      data_.activeId = -1
    }
  })
}
const updateDragingList = (newTag: any, list: any) => {
  const index = list.findIndex((item: any) => item.__config__.formId === data_.activeId)
  if (index > -1) {
    list.splice(index, 1, newTag)
  } else {
    list.forEach((item: any) => {
      if (Array.isArray(item.__config__.children)) updateDragingList(newTag, item.__config__.children)
    })
  }
}

/** ======== 预览 =========  */
const preViewRef = ref()
const preview = () => {
  preViewData.value = {
    ...data_.formConf,
    compsList: cloneDeep(data_.dragingList),
  }
  data_.visible = true
}
const closeView = () => {
  data_.visible = false
}

const viewSubmit = () => {
  preViewRef.value.validate().then((res: any) => {
    message.success('测试成功 ' + JSON.stringify(res))
  })
}
</script>

<style lang='less' scoped>
.design-index {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.form-design {
  width: 100%;
  flex: 1;
  background-color: #fff;
  overflow: hidden;
  display: grid;
  grid-template-columns: 260px auto 360px;
}

.form-design-left {
  height: 100%;
  border-right: 1px solid #f1e8e8;
  overflow: hidden;

  .left-scrollbar {
    height: 100%;
    overflow-x: auto;

    .components-list {
      padding: 8px 16px;
      box-sizing: border-box;
      height: 100%;

      .components-title {
        font-size: 14px;
        color: #222;
        margin: 6px 2px;

        .svg-icon {
          color: #666;
          font-size: 18px;
        }
      }

      .components-draggable {
        padding-bottom: 20px;
      }

      .components-item {
        display: inline-block;
        width: 48%;
        margin: 1%;
        transition: transform 0ms !important;

        .components-info {
          padding: 8px 10px;
          color: #000;
          background: #f6f7ff;
          font-size: 12px;
          cursor: move;
          border: 1px dashed #f6f7ff;
          border-radius: 3px;

          .svg-icon {
            color: #777;
            font-size: 15px;
          }

          &:hover {
            border: 1px dashed #787be8;
            color: #787be8;

            .svg-icon {
              color: #787be8;
            }
          }
        }
      }
    }
  }
}

.form-design-center {
  height: 100%;
  box-sizing: border-box;
  overflow: hidden;

  .center-scrollbar {
    height: 100%;
    border-left: 1px solid #f1e8e8;
    border-right: 1px solid #f1e8e8;
    box-sizing: border-box;
    overflow-y: auto;

    .form-design-center-row {
      width: 100%;
      height: 100%;
      padding: 12px 12px 15px 12px;
      box-sizing: border-box;

      &>.ant-form {
        width: 100%;
        height: 100%;
      }

      .draggable-box {
        width: 100%;
        height: 100%;
        position: relative;

        .sortable-ghost {
          position: relative;
          display: block;
          overflow: hidden;

          &::before {
            content: " ";
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            height: 3px;
            background: rgb(89, 89, 223);
            z-index: 2;
          }
        }

        .components-item.sortable-ghost {
          width: 100%;
          height: 60px;
          background-color: #f6f7ff;
        }
      }

      .empty-info {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        text-align: center;
        font-size: 18px;
        color: #ccb1ea;
        letter-spacing: 4px;
      }
    }
  }
}
</style>
